/*******************************************************************************
 * \brief 解析一款.ttf字体，将各种索引信息存到内存中；取出一个指定汉字的字模；
 *        解析字模的矢量数据，将矢量数据位图化并显示（或者保存为图片）
 * \details 使用C语言，不使用操作系统中与字体相关的第三方库；TTF文件格式的详细描述见：
 *          https://developer.apple.com/fonts/TrueType-Reference-Manual
 * \author 将狼才鲸
 * \date 2022-10-12
 * \note File format: UTF-8
 * \warning 代码未完成，工作已暂停
 ******************************************************************************/

/********************************** 头文件 ************************************/
#include <stdio.h> /* printf fopen ftell fread fclose fflush FILE */
#include <stdint.h> /* uint32_t */
#include <string.h> /* memcpy */

/**
 * .ttf的文件结构为：
 * 整个文件是由不同的表组成的，每个表有四个字母的表名（和mp4容器格式类似）；
 * 整个文件的格式称之为sfnt，sfnt不是一个具体的表，这里指整个文件；
 * 文件的组成：文件头（里面有表的总数目） + N张表
 * 具体的表tag有：DSIG, GSUB, OS/2, cmap, cvt, fpgm, gasp, glyf, head, hhea, hmtx, loca, maxp, name, post, prep, vhea, vmtx
 * 有些表里面有子表。
 */

/********************************** 宏定义 ************************************/
#define USE_STATIC_MEMORY 1	/* 1：使用静态内存分配，不使用malloc */
#define MAX_NUM_TABLES 32	/* 如果使用静态内存，这里最多预先支持32个子表 */
#define MKTAG(a, b, c, d) ((a) | ((b) << 8) | ((c) << 16) | ((unsigned)(d) << 24))

/**
 * \brief 用于大小端转换的宏定义函数，从Linux GNU中拷贝而来
 * \details 默认当前系统是32位系统
 * Based on byteswap.h from GNU C Library
 * Macros to swap the order of bytes in integer values.
 * Copyright (C) 1997-2013 Free Software Foundation, Inc.
 * This file is part of the GNU C Library.
 */
#define uswap_16(x) ((unsigned short int) \
    ((((x) & 0xff00) >> 8) | \
     (((x) & 0x00ff) << 8)))

#define uswap_32(x) \
    ((((x) & 0xff000000) >> 24) | \
     (((x) & 0x00ff0000) >>  8) | \
     (((x) & 0x0000ff00) <<  8) | \
     (((x) & 0x000000ff) << 24))

# define uswap_64(x) \
    ((((x) & 0xff00000000000000ull)>> 56)  | \
     (((x) & 0x00ff000000000000ull) >> 40) | \
     (((x) & 0x0000ff0000000000ull) >> 24) | \
     (((x) & 0x000000ff00000000ull) >> 8)  | \
     (((x) & 0x00000000ff000000ull) << 8)  | \
     (((x) & 0x0000000000ff0000ull) << 24) | \
     (((x) & 0x000000000000ff00ull) << 40) | \
     (((x) & 0x00000000000000ffull) << 56))

/********************************** 结构体 ************************************/
/**
 * \brief .ttf文件里面的一些数据结构
 * \details 和TTF sfnt封装格式基本上是一一对应的，但不是完全对应的，所以这些结构体
 *          也不需要1字节对齐；里面的元素都是一个一个读出来，不是整体赋值
 */

typedef struct _table_directoty {
	uint32_t tag;		/* 4-byte identifier */
	uint32_t checkSum;	/* checksum for this table */
	uint32_t offset;	/* offset from beginning of sfnt */
	uint32_t length;	/* length of this table in byte (actual length not padded length) */
} TABLE_DIRECTORY_T;

typedef struct _ttf_file {
	/* 从这里开始，结构体中内容和.ttf文件中一致 */
	/* Table 4 : The offset subtable from https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html */
	uint32_t scalerType;	/* 缩放器类型，Windows必须为0x00010000，其它允许的值有'true' (0x74727565)，'typ1' (0x74797031)，'OTTO' (0x4F54544F)，其它值不支持 */
	uint16_t numTables;		/* number of tables */
	uint16_t searchRange;	/* (maximum power of 2 <= numTables)*16 */
	uint16_t entrySelector;	/* log2(maximum power of 2 <= numTables) */
	uint16_t rangeShift;	/* numTables*16-searchRange */

	/* Table 5: The table directory */
#if USE_STATIC_MEMORY
	TABLE_DIRECTORY_T table_directory[MAX_NUM_TABLES];	/* 静态内存分配时使用 */
#endif
	TABLE_DIRECTORY_T *p_table_directory;				/* 动态内存分配时使用 */

	/* 从这里开始，只是描述.ttf其中一个表的参数，和真正文件中的内容不是一一对应的 */
	/* The 'head' table from https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6head.html */
	uint32_t head_version;	/* 0x00010000 if (version 1.0) */
	uint32_t fontRevision;	/* set by font manufacturer */
	/**
		To compute: set it to 0, calculate the checksum for the table and put it in the table directory,
		sum the entire font as a uint32_t, then store . (The checksum for the table will be wrong as a result.
		That is OK; do not reset it.)'head'0xB1B0AFBA - sum'head'
	*/
	uint32_t checkSumAdjustment;
	uint32_t magicNumber;	/* set to 0x5F0F3CF5 */
	/**
		bit 0 - y value of 0 specifies baseline
		bit 1 - x position of left most black bit is LSB
		bit 2 - scaled point size and actual point size will differ (i.e. 24 point glyph differs from 12 point glyph scaled by factor of 2)
		bit 3 - use integer scaling instead of fractional
		bit 4 - (used by the Microsoft implementation of the TrueType scaler)
		bit 5 - This bit should be set in fonts that are intended to e laid out vertically, and in which the glyphs have been drawn such that an x-coordinate of 0 corresponds to the desired vertical baseline.
		bit 6 - This bit must be set to zero.
		bit 7 - This bit should be set if the font requires layout for correct linguistic rendering (e.g. Arabic fonts).
		bit 8 - This bit should be set for an AAT font which has one or more metamorphosis effects designated as happening by default.
		bit 9 - This bit should be set if the font contains any strong right-to-left glyphs.
		bit 10 - This bit should be set if the font contains Indic-style rearrangement effects.
		bits 11-13 - Defined by Adobe.
		bit 14 - This bit should be set if the glyphs in the font are simply generic symbols for code point ranges, such as for a last resort font.
	*/
	uint16_t flags;
	uint16_t unitsPerEm;	/* range from 64 to 16384 */
	int64_t created;		/* international date */
	int64_t modified;		/* international date */
	int16_t xMin;			/* for all glyph bounding boxes */
	int16_t yMin;			/* for all glyph bounding boxes */
	int16_t xMax;			/* for all glyph bounding boxes */
	int16_t yMax;			/* for all glyph bounding boxes */
	/**
		bit 0 bold
		bit 1 italic
		bit 2 underline
		bit 3 outline
		bit 4 shadow
		bit 5 condensed (narrow)
		bit 6 extended
	*/
	uint16_t macStyle;
	uint16_t lowestRecPPEM;	/* smallest readable size in pixels */
	/**
		0 Mixed directional glyphs
		1 Only strongly left to right glyphs
		2 Like 1 but also contains neutrals
		-1 Only strongly right to left glyphs
		-2 Like -1 but also contains neutrals
	*/
	int16_t fontDirectionHint;
	int16_t indexToLocFormat;	/* 0 for short offsets, 1 for long */
	int16_t glyphDataFormat;	/* 0 for current format */

	/* The 'maxp' table from https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6maxp.html */
	int32_t maxp_version;			/* 0x00010000 (1.0) */
	uint16_t numGlyphs;				/* the number of glyphs in the font */
	uint16_t maxPoints;				/* points in non-compound glyph */
	uint16_t maxContours;			/* contours in non-compound glyph */
	uint16_t maxComponentPoints;	/* points in compound glyph */
	uint16_t maxComponentContours;	/* contours in compound glyph */
	uint16_t maxZones;				/* set to 2 */
	uint16_t maxTwilightPoints;		/* points used in Twilight Zone (Z0) */
	uint16_t maxStorage;			/* number of Storage Area locations */
	uint16_t maxFunctionDefs;		/* number of FDEFs */
	uint16_t maxInstructionDefs;	/* number of IDEFs */
	uint16_t maxStackElements;		/* maximum stack depth */
	uint16_t maxSizeOfInstructions;	/* byte count for glyph instructions */
	uint16_t maxComponentElements;	/* number of glyphs referenced at top level */
	uint16_t maxComponentDepth;		/* levels of recursion, set to 0 if font has only simple glyphs */

	/* glyf表的起始地址 */
	int32_t glyf_offset;
} TTF_FILE_T;


/********************************* 全局变量 ***********************************/
#if USE_STATIC_MEMORY
#	define MEMORY_LENGTH (32 * 1024 * 1024) /* 开辟32M空间，因为字库文件就有十几M */
static char ttf_data[MEMORY_LENGTH];
#endif /* USE_STATIC_MEMORY */

/********************************* 内部函数 ***********************************/
static void buffer_r64(char *buf, int *offset, uint64_t *val)
{
	uint64_t tmp;
	memcpy(&tmp, buf + (*offset), sizeof(uint64_t));
	*offset = (*offset + sizeof(uint64_t));
	*val = uswap_64(tmp);
}

static void buffer_r32(char *buf, int *offset, uint32_t *val)
{
	uint32_t tmp;
	memcpy(&tmp, buf + (*offset), sizeof(uint32_t));
	*offset = (*offset + sizeof(uint32_t));
	*val = uswap_32(tmp);
}

static void buffer_r16(char *buf, int *offset, uint16_t *val)
{
	uint16_t tmp;
	memcpy(&tmp, buf + (*offset), sizeof(uint16_t));
	*offset = (*offset + sizeof(uint16_t));
	*val = uswap_16(tmp);
}

/**
 * \brief 处理整个.ttf文件
 * \details 不能直接读取整个结构体，因为.ttf文件中是用的MacOS的大端模式存放的值，
 *          而Windows和Linux是小端模式，所以结构体内容不能直接拷贝，需要一个字节
 *          一个字节的处理
 */
static int ttf_parse(TTF_FILE_T *file, char *buffer)
{
	int offset = 0; /* 当前正在处理的文件位置 */
	int i, j;
	unsigned int k;

	/* 1. 赋值Table 4 : The offset subtable */
	buffer_r32(buffer, &offset, &file->scalerType);
	if (file->scalerType != 0x00010000) { /* Windows时必须为这个值 */
		printf("Err: .ttf file error, scalerType is 0x%08x, must be 0x00010000\n", file->scalerType);
		return -1;
	}

	buffer_r16(buffer, &offset, &file->numTables);		/* number of tables */
	buffer_r16(buffer, &offset, &file->searchRange);	/* (maximum power of 2 <= numTables)*16 */
	buffer_r16(buffer, &offset, &file->entrySelector);	/* log2(maximum power of 2 <= numTables) */
	buffer_r16(buffer, &offset, &file->rangeShift);		/* numTables*16-searchRange */
#if USE_STATIC_MEMORY
	if (file->numTables > MAX_NUM_TABLES) {
		printf("Err: the .ttl num tables %d is large than static buffer num %d\n", file->numTables, MAX_NUM_TABLES);
		return -1;
	}
	file->p_table_directory = file->table_directory;
#else
	file->p_table_directory = malloc(file->numTables * sizeof(TABLE_DIRECTORY_T));
	if (NULL == file->p_table_directory) {
		printf("Err: malloc %d error!\n", file->numTables * sizeof(TABLE_DIRECTORY_T));
	}
#endif
	printf("table num: %d, tag: ", file->numTables);

	/* 2. 赋值Table 5: The table directory */
	for (i = 0; i < file->numTables; i++) {
		memcpy(&file->p_table_directory[i].tag, buffer + offset, sizeof(uint32_t));
		offset += sizeof(uint32_t);
		buffer_r32(buffer, &offset, &file->p_table_directory[i].checkSum);	/* checksum for this table */
		buffer_r32(buffer, &offset, &file->p_table_directory[i].offset);	/* offset from beginning of sfnt */
		buffer_r32(buffer, &offset, &file->p_table_directory[i].length);	/* length of this table in byte (actual length not padded length) */
	}

	/* 3. 找到并处理head表 */
	TABLE_DIRECTORY_T *ptable = NULL;
	for (i = 0; i < file->numTables; i++) {
		if (file->p_table_directory[i].tag == MKTAG('h', 'e', 'a', 'd')) {
			ptable = &file->p_table_directory[i];
		}
		printf("%c%c%c%c ", file->p_table_directory[i].tag & 0xFF, file->p_table_directory[i].tag >> 8 & 0xFF, file->p_table_directory[i].tag >> 16 & 0xFF, file->p_table_directory[i].tag >> 24 & 0xFF);
	}
	printf("\n");
	if (NULL == ptable) {
		printf("Err: no 'head' tag in .ttf file!\n");
		return -1;
	}
	offset = ptable->offset;

	buffer_r32(buffer, &offset, &file->head_version);	/* 0x00010000 if (version 1.0) */
	buffer_r32(buffer, &offset, &file->fontRevision);	/* set by font manufacturer */
	buffer_r32(buffer, &offset, &file->checkSumAdjustment);
	buffer_r32(buffer, &offset, &file->magicNumber);	/* set to 0x5F0F3CF5 */
	buffer_r16(buffer, &offset, &file->flags);
	buffer_r16(buffer, &offset, &file->unitsPerEm);		/* range from 64 to 16384 */
	buffer_r64(buffer, &offset, &file->created);		/* international date */
	buffer_r64(buffer, &offset, &file->modified);		/* international date */
	buffer_r16(buffer, &offset, &file->xMin);			/* for all glyph bounding boxes */
	buffer_r16(buffer, &offset, &file->yMin);			/* for all glyph bounding boxes */
	buffer_r16(buffer, &offset, &file->xMax);			/* for all glyph bounding boxes */
	buffer_r16(buffer, &offset, &file->yMax);			/* for all glyph bounding boxes */
	buffer_r16(buffer, &offset, &file->macStyle);
	buffer_r16(buffer, &offset, &file->lowestRecPPEM);	/* smallest readable size in pixels */
	buffer_r16(buffer, &offset, &file->fontDirectionHint);
	buffer_r16(buffer, &offset, &file->indexToLocFormat);	/* 0 for short offsets, 1 for long */
	buffer_r16(buffer, &offset, &file->glyphDataFormat);	/* 0 for current format */

	/* 4. 处理maxp table */
	ptable = NULL;
	for (i = 0; i < file->numTables; i++) {
		if (file->p_table_directory[i].tag == MKTAG('m', 'a', 'x', 'p')) {
			ptable = &file->p_table_directory[i];
		}
	}
	if (NULL == ptable) {
		printf("Err: no 'maxp' tag in .ttf file!\n");
		return -1;
	}
	offset = ptable->offset;

	buffer_r32(buffer, &offset, &file->maxp_version);			/* 0x00010000 (1.0) */
	buffer_r16(buffer, &offset, &file->numGlyphs);				/* the number of glyphs in the font */
	printf("The number of glyphs: %d\n", file->numGlyphs);
	buffer_r16(buffer, &offset, &file->maxPoints);				/* points in non-compound glyph */
	buffer_r16(buffer, &offset, &file->maxContours);			/* contours in non-compound glyph */
	buffer_r16(buffer, &offset, &file->maxComponentPoints);		/* points in compound glyph */
	buffer_r16(buffer, &offset, &file->maxComponentContours);	/* contours in compound glyph */
	buffer_r16(buffer, &offset, &file->maxZones);				/* set to 2 */
	buffer_r16(buffer, &offset, &file->maxTwilightPoints);		/* points used in Twilight Zone (Z0) */
	buffer_r16(buffer, &offset, &file->maxStorage);				/* number of Storage Area locations */
	buffer_r16(buffer, &offset, &file->maxFunctionDefs);		/* number of FDEFs */
	buffer_r16(buffer, &offset, &file->maxInstructionDefs);		/* number of IDEFs */
	buffer_r16(buffer, &offset, &file->maxStackElements);		/* maximum stack depth */
	buffer_r16(buffer, &offset, &file->maxSizeOfInstructions);	/* byte count for glyph instructions */
	buffer_r16(buffer, &offset, &file->maxComponentElements);	/* number of glyphs referenced at top level */
	buffer_r16(buffer, &offset, &file->maxComponentDepth);		/* levels of recursion, set to 0 if font has only simple glyphs */

	/* 5. 处理cmap table，cmap (character code mapping)是很重要的一个表，包含了所有字模数据 */
	/**
	 * \brief cmap存储每个字的编码到字形数据的映射
	 * \details 因为文字有不同的编码，如GB2312、UTF-8，所以一个cmap可能有多个子表
	 *          索引0存储暂不支持显示的字符编码，索引-1（0xFFFF）存储已被删除的字符编码
	 * \note The 'cmap' table from https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6cmap.html
	 */
	ptable = NULL;
	for (i = 0; i < file->numTables; i++) {
		if (file->p_table_directory[i].tag == MKTAG('c', 'm', 'a', 'p')) {
			ptable = &file->p_table_directory[i];
		}
	}
	if (NULL == ptable) {
		printf("Err: no 'cmap' tag in .ttf file!\n");
		return -1;
	}
	offset = ptable->offset;
	int entry_offset = offset;

	/* 先获取cmap中有几张子表，一般英文字库只有一张，中文可能有三张：GB2312、UTF-8等 */
	uint16_t version;			/* Version number (Set to zero) */
	uint16_t numberSubtables;	/* Number of encoding subtables */

	buffer_r16(buffer, &offset, &version);
	buffer_r16(buffer, &offset, &numberSubtables);
	printf("CMAP subtable numbers: %d\n", numberSubtables);

	/* 获取每个子表中的元素，找到要用的那张子表 */
	uint16_t platformID;		/* Platform identifier */
	uint16_t platformSpecificID;/* Platform-specific encoding identifier */
	uint32_t subbable_offset;	/* Offset of the mapping table */
	for (i = 0; i < numberSubtables; i++) {
		/**
		 * platformID:
		 * 0	Unicode	Indicates Unicode version.
		 * 1	Macintosh	Script Manager code.
		 * 2	(reserved; do not use)
		 * 3	Microsoft	Microsoft encoding.
		 */
		buffer_r16(buffer, &offset, &platformID);

		/**
		 * platformSpecificID:
		 * UNICODE:
		 * 0	Version 1.0 semantics
		 * 1	Version 1.1 semantics
		 * 2	ISO 10646 1993 semantics (deprecated)
		 * 3	Unicode 2.0 or later semantics (BMP only)
		 * 4	Unicode 2.0 or later semantics (non-BMP characters allowed)
		 * 5	Unicode Variation Sequences
		 * 6	Last Resort
		 *
		 * Windows:
		 * 0	Symbol
		 * 1	Unicode BMP-only (UCS-2)
		 * 2	Shift-JIS
		 * 3	PRC
		 * 4	BigFive
		 * 5	Johab
		 * 10	Unicode UCS-4
		 */
		buffer_r16(buffer, &offset, &platformSpecificID);
		/* 测试文件中，只有simkai.ttf英文字体的值是3和1，zeichenssw.ttf中文字体的值是0、0不符合要求，先屏蔽掉这几行代码 */
		// if (!((platformID == 0 && platformSpecificID == 3) /* Unicode + Unicode2.0 */
			// || (platformID == 3 && platformSpecificID == 1))) /* Windows + Unicode BMP */
			// continue;

		buffer_r32(buffer, &offset, &subbable_offset);
		offset = entry_offset + subbable_offset;

		/**
		 * Each 'cmap' subtable is in one of nine currently available formats. 
		 * These are format 0, format 2, format 4, format 6, format 8, format 10, format 12, 
		 * format 13, and format 14 described in the next section
		 * cmap子表有不同的格式，不同的格式中按不同的布局存储内容；实际字符编码有定长和变长之分；
		 * 格式4支持固定16位数据，如RG2312；格式12支持16/32位混合，如UTF-8。
		 * 以下的变量都是'cmap' format 4中的
		 */
		uint16_t format;					/* Format number is set to 4 */
		buffer_r16(buffer, &offset, &format);
		if (format != 4) /* 必须找出Windows GB2312的编码，id为4 */
			continue;

		printf("CMAP subtable type is %d(GB2312 if 4)\n", format);

		uint16_t length;					/* Length of subtable in bytes */
		uint16_t language;					/* Language code (see above) */
		uint16_t segCountX2;				/* 2 * segCount */
		uint16_t searchRange;				/* 2 * (2**FLOOR(log2(segCount))) */
		uint16_t entrySelector;				/* log2(searchRange/2) */
		uint16_t rangeShift;				/* (2 * segCount) - searchRange */

		buffer_r16(buffer, &offset, &length);
		buffer_r16(buffer, &offset, &language);
		buffer_r16(buffer, &offset, &segCountX2);
		printf("Word total count: %d\n", segCountX2 >> 1); // is / 2
		uint16_t segCount = segCountX2 >> 1; // is / 2

		buffer_r16(buffer, &offset, &searchRange);
		buffer_r16(buffer, &offset, &entrySelector);
		buffer_r16(buffer, &offset, &rangeShift);

#define MAX_SEG_COUNT 4
#if USE_STATIC_MEMORY
		if (segCount > MAX_SEG_COUNT) {
			printf("Err: the seg count %d is large than static %d!\n", segCountX2 / 2, MAX_SEG_COUNT);
			return -1;
		}
		uint16_t endCode[MAX_SEG_COUNT];	/* Ending character code for each segment, last = 0xFFFF. 每段的结束文字编码 */
		uint16_t reservedPad;				/* This value should be zero */
		uint16_t startCode[MAX_SEG_COUNT];	/* Starting character code for each segment，每段的开始文字编码 */
		uint16_t idDelta[MAX_SEG_COUNT];	/* Delta for all character codes in segment，每个文字字形数据的固定长度，也是偏移量 */
		uint16_t idRangeOffset[MAX_SEG_COUNT];	/* Offset in bytes to glyph indexArray, or 0，总共有多少段文字 */
		//uint16_t glyphIndexArray[variable];	/* Glyph index array */
#else
		uint16_t *endCode = malloc(segCount * sizeof(uint16_t));
		uint16_t reservedPad;
		uint16_t *startCode = malloc(segCount * sizeof(uint16_t));
		uint16_t *idDelta = malloc(segCount * sizeof(uint16_t));
		uint16_t *idRangeOffset = malloc(segCount * sizeof(uint16_t));
		//uint16_t glyphIndexArray[variable];
#endif

		for (j = 0; j < segCount; j++)
			buffer_r16(buffer, &offset, &endCode[j]);
		buffer_r16(buffer, &offset, &reservedPad);
		for (j = 0; j < segCount; j++)
			buffer_r16(buffer, &offset, &startCode[j]);
		for (j = 0; j < segCount; j++)
			buffer_r16(buffer, &offset, &idDelta[j]);
		for (j = 0; j < segCount; j++)
			buffer_r16(buffer, &offset, &idRangeOffset[j]);

		int tmp_pos = offset;
		for (j = 0; j < segCount; j++)
		{
			/*！！！ 此段代码未完成，有bug */
			/* 按文字段进行循环，以0开始，以0xFFFF结束（但是zeichenssw.ttf字体没有从0开始） */
			if (idRangeOffset[j] == 0xFFFF)
				break;
			if (idRangeOffset[j] == 0) {
				for (k = startCode[j]; k <= endCode[j]; k++) {
					/* glyphIndexAddress = idRangeOffset[i] + 2 * (c - startCode[i]) + (Ptr) &idRangeOffset[i] */
					/* glyphIndex = *( &idRangeOffset[i] + idRangeOffset[i] / 2 + (c - startCode[i]) ) */
					//file->glyphIndexAddress[k] = k + idDelta[j];
					//file->glyphIndex[k + idDelta[j]] = k;
				}
			} else {
				for (k = startCode[j]; k <= endCode[j]; k++) {
					//offset = tmp_pos + idRangeOffset[j];
					//offset += sizeof(uint32_t);
				}
			}
		}
	}

	/* 6. 处理loca table，https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6loca.html */
	ptable = NULL;
	for (i = 0; i < file->numTables; i++) {
		if (file->p_table_directory[i].tag == MKTAG('l', 'o', 'c', 'a')) {
			ptable = &file->p_table_directory[i];
		}
	}
	if (NULL == ptable) {
		printf("Err: no 'loca' tag in .ttf file!\n");
		return -1;
	}
	offset = ptable->offset;

	/* 存储字形的偏移量 */
	int glyph_number = file->numGlyphs;
	/* 将几万个偏移量全部存起来 */


	/* 7. 处理glyf table，https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html */
	ptable = NULL;
	for (i = 0; i < file->numTables; i++) {
		if (file->p_table_directory[i].tag == MKTAG('g', 'l', 'y', 'f')) {
			ptable = &file->p_table_directory[i];
		}
	}
	if (NULL == ptable) {
		printf("Err: no 'glyf' tag in .ttf file!\n");
		return -1;
	}
	offset = ptable->offset;
	file->glyf_offset = ptable->offset;

	return 0;
}

/********************************* 接口函数 ***********************************/
int main(int argc, char *argv[])
{
	if (argc > 0)
		printf("Program name: %s\n", argv[0]);

	printf("--------\n");
	printf("- 使用./demo ttf字体文件名字\n");
	printf("--------\n");

	/* 默认传入的第一个参数是ttf字体文件的路径和名字 */
	char *ttf_filename;
	if (argc > 1) {
		ttf_filename = argv[1]; /* 路径名可能要从char*转换成wchar* */
		printf("The input .ttf file name is %s\n", ttf_filename);
	} else {
		printf("Warning: please input .ttf file name");
		return 0;
	}

	/* 1. 打开字体文件并获取文件内容 */
	FILE *fp = fopen(ttf_filename, "rb"); /* 只读的方式打开文件，如果文件不存在则返回错误 */
	if (NULL == fp) {
		printf("Err: %s open fail!\n", ttf_filename);
		return 0;
	}

	/* 获取文件长度 */
	fseek(fp, 0, SEEK_END); /* 跳到文件末尾 */
	int fft_file_len = ftell(fp); /* 返回在文件中的当前位置 */
	fseek(fp, 0, SEEK_SET); /* 跳转到文件开头 */
	printf("The file length is %d\n", fft_file_len);

#if USE_STATIC_MEMORY
	if (fft_file_len > MEMORY_LENGTH) {
		printf("Err: use static memory, the ttf file %d is large than buffer %d!\n", fft_file_len, MEMORY_LENGTH);
		fclose(fp);
		return 0;
	}
#endif

	/* 读取整个文件 */
	size_t ret = fread(ttf_data, 1, fft_file_len, fp);
	if (ret < fft_file_len) {
		printf("Err: file read length %d error, want %d!\n", ret, fft_file_len);
		fclose(fp);
		return 0;
	}

	fclose(fp);

	/* 2. 解析ttf字库文件 */
	TTF_FILE_T ttf_file;
	ttf_parse(&ttf_file, ttf_data);

	/* 3. 进行字库测试 */
	//ttf_print_a_word(ttf_data);

	return 0;
}